package io.youngledo.usb.storage;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;

/// **对象存储助手类**
///
/// 提供通用的对象存储处理逻辑，减少各个实现类中的重复代码
///
public class ObjectStorageHelper {

    /// **计算显示名称**
    ///
    /// 移除前缀，返回相对路径名称
    ///
    /// **参数:**
    /// - `fullKey` - 完整的对象键
    /// - `prefix` - 前缀（可为null或空）
    ///
    /// **返回值:** 显示名称
    ///
    public static String calculateDisplayName(String fullKey, String prefix) {
        if (prefix == null || prefix.isEmpty()) {
            return fullKey;
        }

        if (fullKey.startsWith(prefix)) {
            return fullKey.substring(prefix.length());
        }

        return fullKey;
    }

    /// **检查显示名称是否有效**
    ///
    /// 判断显示名称是否为空或只包含分隔符
    ///
    /// **参数:**
    /// - `displayName` - 显示名称
    ///
    /// **返回值:** true 如果有效（非空且不是单独的分隔符）
    ///
    public static boolean isValidDisplayName(String displayName) {
        return displayName != null
            && !displayName.isEmpty()
            && !displayName.equals("/");
    }

    /// **确保目录名称以斜杠结尾**
    ///
    /// **参数:**
    /// - `name` - 目录名称
    ///
    /// **返回值:** 以 `/` 结尾的目录名称
    ///
    public static String ensureDirectorySuffix(String name) {
        if (name == null || name.isEmpty()) {
            return name;
        }
        return name.endsWith("/") ? name : name + "/";
    }

    /// **移除目录名称末尾的斜杠**
    ///
    /// **参数:**
    /// - `name` - 目录名称
    ///
    /// **返回值:** 移除末尾 `/` 后的目录名称
    ///
    public static String removeDirectorySuffix(String name) {
        if (name == null || !name.endsWith("/")) {
            return name;
        }
        return name.substring(0, name.length() - 1);
    }

    /// **检查是否应该跳过该对象**
    ///
    /// 某些对象是前缀本身或空对象，应该跳过
    ///
    /// **参数:**
    /// - `objectKey` - 对象键
    /// - `prefix` - 前缀
    ///
    /// **返回值:** true 如果应该跳过
    ///
    public static boolean shouldSkipObject(String objectKey, String prefix) {
        // 跳过前缀本身（如果它是一个目录标记）
        return objectKey != null && objectKey.equals(prefix);
    }

    /// **处理对象键并返回有效的显示名称**
    ///
    /// 组合多个处理步骤：移除前缀、验证有效性
    ///
    /// **参数:**
    /// - `objectKey` - 完整的对象键
    /// - `prefix` - 前缀（可为null或空）
    ///
    /// **返回值:** 显示名称，如果无效则返回null
    ///
    public static String processObjectKey(String objectKey, String prefix) {
        // 跳过前缀本身
        if (shouldSkipObject(objectKey, prefix)) {
            return null;
        }

        String displayName = calculateDisplayName(objectKey, prefix);

        // 检查有效性
        if (!isValidDisplayName(displayName)) {
            return null;
        }

        return displayName;
    }

    /// **处理公共前缀（文件夹）并返回有效的显示名称**
    ///
    /// 专门用于处理非递归模式下的公共前缀
    ///
    /// **参数:**
    /// - `commonPrefix` - 公共前缀（通常以 `/` 结尾）
    /// - `prefix` - 前缀（可为null或空）
    ///
    /// **返回值:** 显示名称，如果无效则返回null
    ///
    public static String processCommonPrefix(String commonPrefix, String prefix) {
        String displayName = calculateDisplayName(commonPrefix, prefix);

        // 检查有效性
        if (!isValidDisplayName(displayName)) {
            return null;
        }

        return displayName;
    }

    /// **处理公共前缀列表并转换为目录对象列表**
    ///
    /// 通用方法，适用于所有返回公共前缀的存储服务
    ///
    /// **参数:**
    /// - `commonPrefixes` - 公共前缀列表
    /// - `prefix` - 当前前缀
    /// - `removeTrailingSuffix` - 是否移除末尾的 `/`（某些实现需要，某些不需要）
    ///
    /// **返回值:** 目录对象列表
    ///
    public static List<StorageObject> processCommonPrefixes(
            Iterable<String> commonPrefixes,
            String prefix,
            boolean removeTrailingSuffix) {

        List<StorageObject> result = new ArrayList<>();

        for (String commonPrefix : commonPrefixes) {
            String displayName = processCommonPrefix(commonPrefix, prefix);
            if (displayName == null) {
                continue;
            }

            // 根据需要移除末尾的斜杠
            if (removeTrailingSuffix) {
                displayName = removeDirectorySuffix(displayName);
            }

            result.add(StorageObject.directory(commonPrefix, displayName));
        }

        return result;
    }

    /// **处理对象列表并转换为 StorageObject 列表**
    ///
    /// 通用方法，使用函数式接口来适配不同的对象类型
    ///
    /// **类型参数:**
    /// - `T` - 原始对象类型（如 OSSObjectSummary, ObsObject 等）
    ///
    /// **参数:**
    /// - `objects` - 原始对象列表
    /// - `prefix` - 当前前缀
    /// - `objectMapper` - 将原始对象映射为 StorageObject 的函数
    ///
    /// **返回值:** StorageObject 列表
    ///
    public static <T> List<StorageObject> processObjects(
            Iterable<T> objects,
            String prefix,
            Function<T, String> keyExtractor,
            ObjectMapper<T> objectMapper) {

        List<StorageObject> result = new ArrayList<>();

        for (T obj : objects) {
            String objectKey = keyExtractor.apply(obj);
            String displayName = processObjectKey(objectKey, prefix);

            if (displayName == null) {
                continue;
            }

            StorageObject storageObject = objectMapper.map(obj, objectKey, displayName);
            if (storageObject != null) {
                result.add(storageObject);
            }
        }

        return result;
    }

    /// **对象映射器函数式接口**
    ///
    /// 用于将特定存储服务的对象类型转换为通用的 StorageObject
    ///
    @FunctionalInterface
    public interface ObjectMapper<T> {
        /// **将原始对象映射为 StorageObject**
        ///
        /// **参数:**
        /// - `object` - 原始对象
        /// - `objectKey` - 对象键（完整路径）
        /// - `displayName` - 显示名称（已处理过的）
        ///
        /// **返回值:** StorageObject，如果不应包含则返回null
        ///
        StorageObject map(T object, String objectKey, String displayName);
    }
}
